﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.IO;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using EEst.Tools.VSPackageCrossCompileNMake90;

using EnvDTE;
using EnvDTE80;

using IServiceProvider = System.IServiceProvider;
using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;


namespace EEst.Tools.VsPackageNMakeAdapter
{
    /// <summary>
    /// Summary description for MyControl.
    /// </summary>
    public partial class MyControl : UserControl
    {
        private MyToolWindow _parent;
        private string nmakePath = null;

        public MyControl(MyToolWindow parent)
        {
            InitializeComponent();
            _parent = parent;

            IDictionary dic = System.Environment.GetEnvironmentVariables();
            foreach (System.Collections.DictionaryEntry de in dic)
            {
                string key = de.Key as string;
                if (key.CompareTo("_ACP_PATH") == 0)
                {
                    string value = de.Value as string;
                    string[] paths = value.Split(new char[] { ';' });
                    for (int i = 0; i < paths.Length; i++)
                    {
                        if (paths[i].EndsWith("\\VC\\bin"))
                        {
                            nmakePath = paths[i];
                            break;
                        }
                    }
                }
                if (nmakePath != null)
                {
                    break;
                }
            }

        }

        /// <summary> 
        /// Let this control process the mnemonics.
        /// </summary>
        protected override bool ProcessDialogChar(char charCode)
        {
              // If we're the top-level form or control, we need to do the mnemonic handling
              if (charCode != ' ' && ProcessMnemonic(charCode))
              {
                    return true;
              }
              return base.ProcessDialogChar(charCode);
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            MessageBox.Show(this,
                            string.Format("We are inside {0}.button1_Click()", this.ToString()),
                            "Cross Compile using nmake");
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private DTE _vs;

        private void MyControl_Load(object sender, EventArgs e)
        {
            _vs = _parent.GetVsService(typeof(DTE)) as DTE;
            Solution solution = _vs.Solution;
            SetupProjectList(solution);
        }

        private void SetupProjectList(Solution solution)
        {
            foreach (Project project in solution.Projects)
            {
                string kind = project.Kind;
                string name = project.Name;
                string path = name;
                if (kind.CompareTo("{66A26720-8FB5-11D2-AA7E-00C04F688DDE}") == 0)
                {
                    SolutionFolder folder = project.Object as SolutionFolder;
                }
                if (project.Object is SolutionFolder)
                {
                    System.Diagnostics.Debug.WriteLine("name:" + project.Name + " is Folder");
                }
                TraverseProject(project, path);
            }
        }

        private void TraverseProject(Project proj,string pathTop)
        {
            foreach (ProjectItem pi in proj.ProjectItems)
            {
                string path = pathTop.ToString();
                if (pi.Object is Project)
                {
                    Project childProj = pi.Object as Project;
                    if (childProj.Object is SolutionFolder)
                    {
                        path += "." + childProj.Name;
                        System.Diagnostics.Debug.WriteLine("Folder -> name:" + childProj.Name + ", kind:" + childProj.Kind);
                        TraverseProject(childProj, path);
                    }
                    else
                    {
                        System.Diagnostics.Debug.WriteLine("Project -> name:" + childProj.Name + ", kind:" + childProj.Kind);
                        if (childProj.Kind.CompareTo(CPPProjectGuid) == 0)
                        {
                            string key = path + "." + childProj.Name;
                            vcppProjects.Add(key, childProj);
                            int id = listBoxProjects.Items.Add(key);
                            string fullName = childProj.FullName;
                            FileInfo fi = new FileInfo(fullName);
                            string makefile = fi.DirectoryName + "\\Makefile.xc";
                            if (System.IO.File.Exists(makefile))
                            {
                                // I want to change item's font color to red!
                            }
                        }
                    }
                }
            }
        }
        private Dictionary<string, Project> vcppProjects = new Dictionary<string, Project>();

        private static string SolutionFolderGuid = "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}";
        private static string CSharpProjectGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
        private static string CPPProjectGuid = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}";
        private static string MakefileName = "Makefile.xc";
        private static string ConfigFileName = "XCConfig.xml";

        private void buttonCompile_Click(object sender, EventArgs e)
        {
            string selectedProject = listBoxProjects.SelectedItem as string;
            Project project = null;
            if (vcppProjects.TryGetValue(selectedProject, out project))
            {
                string projFile = project.FullName;
                FileInfo fi = new FileInfo(projFile);

                System.Diagnostics.Process process = new System.Diagnostics.Process();
                process.StartInfo.FileName = nmakePath + "\\nmake";
                process.StartInfo.Arguments = "/nologo /f " + MakefileName + " all";
                process.StartInfo.RedirectStandardError = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = false;
                process.StartInfo.WorkingDirectory = fi.DirectoryName;
                errorWriter = new StringWriter();
                process.ErrorDataReceived += new
                     System.Diagnostics.DataReceivedEventHandler(ReceiveErrorHandler);
                stdoutWriter = new StringWriter();
                process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(ReceiveStdoutHandler);

                try
                {
                    process.Start();
                    process.BeginErrorReadLine();
                    process.BeginOutputReadLine();
                    process.WaitForExit();
                    int exitCode = process.ExitCode;

                    textBoxStdout.Text = "ExitCode:" + exitCode+@"
";
                    textBoxStdout.Text += stdoutWriter.ToString();

                    dataGridViewCompileError.Rows.Clear();

                    TextReader reader = new StringReader(errorWriter.ToString());
                    string error = reader.ReadLine();
                    while (error != null)
                    {
                        if (error.StartsWith("NMAKE") || error.StartsWith("Stop."))
                        {
                            break;
                        }
                        string[] contents = error.Split(new char[] { ':' });
                        if (contents[1].StartsWith("/")) {
                            string[] temp = contents[0].Split(new char[] {' '});
                            string tryFileName = temp[temp.Length - 1] + ":" + contents[1];
                            if (System.IO.File.Exists(tryFileName))
                            {
                                contents[0] = contents[0].Substring(0, contents[0].Length - temp[temp.Length - 1].Length);
                                contents[1] = tryFileName;
                            }
                            if (String.IsNullOrEmpty(contents[0]))
                            {
                                for (int i = 1; i < contents.Length; i++)
                                {
                                    contents[i - 1] = contents[i];
                                }
                                contents[contents.Length - 1] = "";
                            }
                        }
                        if (contents.Length >= 3)
                        {
                            string fileName = contents[0];
                            string lineNo;
                            string content;
                            if (fileName.StartsWith(MakefileName))
                            {
                                int lineNoLength = fileName.Length - MakefileName.Length - 3;
                                lineNo = fileName.Substring(MakefileName.Length + 1, lineNoLength);
                                fileName = MakefileName;
                                content = contents[1];
                                for (int i = 2; i < contents.Length; i++)
                                {
                                    content += ":" + contents[i];
                                }
                            }
                            else if (fileName.StartsWith(@"In file included from ") || fileName.StartsWith(@"                 from "))
                            {
                                if (String.IsNullOrEmpty(contents[2]))
                                {
                                    lineNo = contents[1];
                                    content = fileName;
                                    fileName = fileName.Substring(@"In file included from ".Length);
                                }
                                else
                                {
                                    content = contents[0];
                                    fileName = contents[1];
                                    lineNo = contents[2];
                                    if (lineNo.EndsWith(","))
                                    {
                                        lineNo = lineNo.Substring(0, lineNo.Length - 1);
                                    }
                                }
                            }
                            else
                            {
                                int num;
                                if (Int32.TryParse(contents[1], out num))
                                {
                                    lineNo = contents[1];
                                    content = contents[2];
                                }
                                else
                                {
                                    lineNo = "";
                                    content = contents[1];
                                }
                                for (int i = 3; i < contents.Length; i++)
                                {
                                    content += ":" + contents[i];
                                }

                            }
                            string[] row = new string[] { fileName, lineNo, content };
                            dataGridViewCompileError.Rows.Add(row);
                        }
                        else if (contents.Length == 2)
                        {
                            string fileName = contents[0];
                            string lineNo;
                            string content="";
                            if (fileName.StartsWith(@"                 from "))
                            {
                                fileName = fileName.Substring(@"                 from ".Length);
                                lineNo = contents[1];
                                content = "from ";
                                if (lineNo.EndsWith(","))
                                {
                                    lineNo = lineNo.Substring(0, lineNo.Length - 1);
                                }
                                string[] row = new string[] { fileName, lineNo, content };
                                dataGridViewCompileError.Rows.Add(row);
                            }
                        }
                        error = reader.ReadLine();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }

        private StringWriter errorWriter = null;

        private void ReceiveErrorHandler(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                errorWriter.WriteLine(e.Data);
            }
        }

        private StringWriter stdoutWriter = null;
        private void ReceiveStdoutHandler(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                stdoutWriter.WriteLine(e.Data);
            }
        }

        private void listBoxProjects_SelectedIndexChanged(object sender, EventArgs e)
        {
            string selected = listBoxProjects.SelectedItem as string;
            Project project = null;
            if (vcppProjects.TryGetValue(selected, out project))
            {
                FileInfo fi = new FileInfo(project.FullName);
                string makefile = fi.DirectoryName + "\\" + MakefileName;
                if (System.IO.File.Exists(makefile))
                {
                    //  buttonBuildMakefile.Enabled = false;
                    buttonCompile.Enabled = true;
                }
                else
                {
                    string configFile = fi.DirectoryName + "\\" + ConfigFileName;
                    if (System.IO.File.Exists(configFile))
                    {
                        //    buttonBuildMakefile.Enabled = true;
                    }
                    else
                    {
                        //    buttonBuildMakefile.Enabled = false;
                    }
                    buttonCompile.Enabled = false;
                }
                buttonBuildMakefile.Enabled = true;
            }
            else
            {
                buttonBuildMakefile.Enabled = false;
                buttonCompile.Enabled = false;
            }
        }

        private void buttonBuildMakefile_Click(object sender, EventArgs e)
        {
            userControlBuildXCMakefilePane.Enabled = false;
            string projectName= listBoxProjects.SelectedItem as string;
            if (!string.IsNullOrEmpty(projectName))
            {
                Project project = null;
                if (vcppProjects.TryGetValue(projectName, out project))
                {
                    userControlBuildXCMakefilePane.Target = project;
                    userControlBuildXCMakefilePane.MakeFile = "Makefile.xc";
                    userControlBuildXCMakefilePane.ConfigFile = "XCConfig.xml";
                    userControlBuildXCMakefilePane.Enabled = true;
                }
            }

            if (listBoxProjects.Items.Count == 0)
            {
                SetupProjectList(_vs.Solution);
            }
        }

        private ProjectItem FindProjectItem(Project project, string itemName)
        {
            foreach (ProjectItem pi in project.ProjectItems)
            {
                ProjectItem result = FindProjectItem(pi, itemName);
                if (result != null)
                {
                    return result;
                }
            }
            return null;
        }
        private ProjectItem FindProjectItem(ProjectItem pi, string itemName)
        {
            if (pi.Name.CompareTo(itemName) == 0)
            {
                return pi;
            }
            foreach (ProjectItem child in pi.ProjectItems)
            {
                ProjectItem result = FindProjectItem(child, itemName);
                if (result != null)
                {
                    return result;
                }
            }
            return null;
        }

        private void dataGridViewCompileError_DoubleClick(object sender, EventArgs e)
        {
             DataGridViewRow row = dataGridViewCompileError.CurrentRow;
             string fileName = row.Cells[0].Value as string;
             string lineNo = row.Cells[1].Value as string;
             if (!String.IsNullOrEmpty(lineNo))
             {
                 try
                 {
                     int lineNum = Int32.Parse(lineNo);

                     string projectName = listBoxProjects.SelectedItem as string;
                     Project project = null;
                     if (vcppProjects.TryGetValue(projectName, out project))
                     {
                         Window window = null;
                         ProjectItem pi = FindProjectItem(project, fileName);
                         if (pi != null)
                         {
                             window = pi.Open(Constants.vsViewKindPrimary);
                         }
                         else
                         {
                             FileInfo fi = new FileInfo(project.FullName);
                             if (fi.Exists)
                             {
                                 string target = fi.DirectoryName + "\\" + fileName;
                                 window = _vs.OpenFile(Constants.vsViewKindPrimary, target);
                             }
                         }
                         if (window != null)
                         {
                             window.Activate();
                             TextWindow tw = window.Object as TextWindow;
                             if (tw is TextWindow)
                             {
                                 TextPane pan = tw.ActivePane;
                                 TextSelection selection = pan.Selection;
                                 selection.GotoLine(lineNum, true);
                             }
                         }
                         else
                         {
                             MessageBox.Show("Invalid File:" + fileName + " or Line:" + lineNo + " in Project:" + projectName);
                         }
                     }
                 }
                 catch (System.Exception ex)
                 {
                     MessageBox.Show("Invalid Line:" + lineNo);
                 }
             }
        }

        private void buttonReflesh_Click(object sender, EventArgs e)
        {
            if (_vs == null)
            {
                _vs = _parent.GetVsService(typeof(DTE)) as DTE;
                
            }
            Solution solution = _vs.Solution;
            listBoxProjects.Items.Clear();
            vcppProjects.Clear();
            SetupProjectList(solution);

        }
    }
}
